{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 这个程序用来实现机器学习 HW1 作业5 要求的线性回归，对要求的三十个数据进行拟合。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 初始化设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始设置\n",
    "import numpy as np\n",
    "import random\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(30,)\n",
      "(30,)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD8CAYAAACMwORRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAFFZJREFUeJzt3X+MHHd5x/H3EyeEowUuYLfFlxg7knFJMcLSKdC6Ej+FHYQS16XgtLSEhlpQoKItFrZAFIEqB6IqqlRaalCaQtWEkAbXLUEuYBASJTSmBtIEGUwojc8pCT9MhTAhhKd/3BysL3u3e3uztzPffb+kk29nZnefzG0+O/vMd74bmYkkqSznjLoASVL9DHdJKpDhLkkFMtwlqUCGuyQVyHCXpAIZ7pJUIMNdkgpkuEtSgc4d1ROvXr06169fP6qnl6RW+vznP/+tzFzTa7uRhfv69es5evToqJ5eklopIr7Rz3a2ZSSpQIa7JBXIcJekAhnuklQgw12SCmS4S1KBDHdJKpDhLkkFGtlFTJKa4eCxGa49fJxTp8+wdnKCPds2sWPL1KjL0jIZ7tIYO3hshn233smZhx4GYOb0GfbdeieAAd9ytmWkMXbt4eM/DfY5Zx56mGsPHx9RRaqL4S6NsVOnzyxpudrDcJfG2NrJiSUtV3sY7tIY27NtExPnrTpr2cR5q9izbdOIKlJdPKEqjbG5k6aOlimP4S6NuR1bplob5g7jXJjhLqmVHMa5OMNdUistNoyzaeE+ik8YhrukVmrLMM5RfcJwtIykVmrLMM5RXShmuEtqpbYM4xzVJwzDXVIr7dgyxf6dm5manCCAqckJ9u/c3Lh++6g+Ydhzl9RabRjGuWfbprN67rAynzAMd0kaolFdKNYz3CPieuDFwP2Z+bQu638HeFN18/vAazLzi7VWKUktNopPGP303G8Ati+y/uvAszPz6cA7gAM11CVJWoaeR+6Z+emIWL/I+n/vuHk7cOHyy5IkLUfdo2WuBj5a82NKkpaothOqEfFcZsP91xfZZjewG2DdunV1PbUkaZ5awj0ing68D7gsM7+90HaZeYCqJz89PZ11PLdUEmc5VF2WHe4RsQ64FfjdzPzK8kuSxpOzHKpOPXvuEXEj8FlgU0ScjIirI+LVEfHqapO3Ak8E/joivhARR4dYr1Qsv6xadepntMyVPda/CnhVbRVJY6otsxyqHZxbRmqItsxyqHYw3KWGaMssh2oH55aRGsIvq1adDHepQdowy6HawbaMJBXII3dpCLwYSaNmuEs182IkNYHhLtVssYuRSg93P7E0h+Eu1WxcL0byE0uzeEJVqtm4Xozk9AnNYrhLNRvXi5HG9RNLUxnuUs12bJli/87NTE1OEMDU5AT7d24uvjUxrp9YmsqeuzQE43gx0p5tm87qucN4fGJpKsNdUi2cPqFZDHdJtRnHTyxNZc9dkgpkuEtSgQx3SSqQPXep4qXzKonhLrG8S+d9U1AT2ZaRGPzS+bk3hZnTZ0h+9qZw8NjMEKuVejPcNdYOHpth6zVHmBnw0nnnU1FT2ZbR2Jrfiumm16XzzqeipvLIXWOr21F3p34unXc+FTWV4a6xtdjRdb+TfY3rDJBqPtsyGltrJye69tqnJif4zN7n9fUYzqeipjLcNbbqmsXQ+VTURIa7xpZH3fVwnH8zGe4aax51L4/fm9pchruGxiO68i02zt+/9WgZ7hqKcTii883Lcf5N5lBIDUXpV2467cAsx/k3l+GuoejniG7u0v8Nez/C1muOtCoYS3/z6pfj/JvLtoyGYqEx5HNHdG1v29iOmOWIo+bqGe4RcT3wYuD+zHxal/UB/CXwIuAHwFWZ+Z91F6p26TWGvO0n4nq9eY0TRxw1Uz9tmRuA7YusvwzYWP3sBv5m+WWp7XZsmWL/zs1MTU4QPPJy/rYf+dqOUNP1PHLPzE9HxPpFNrkCeH9mJnB7RExGxJMy876aalRLLXZE1/YjX9sRaro6eu5TwL0dt09Wywx3LaiuS/9HyXaEmqyOcI8uy7LrhhG7mW3dsG7duhqeWm3lka80XHWE+0ngoo7bFwKnum2YmQeAAwDT09Nd3wA0PjzylYanjnHuh4Dfi1nPAr5nv12SRqufoZA3As8BVkfESeDPgPMAMvM9wG3MDoM8wexQyFcOq1hJUn/6GS1zZY/1Cby2tookScvm9AOSVCDDXZIKZLhLUoGcOEyt4Nzp0tIY7mq8ts8gKY2CbRk1nnOnS0tnuKvx2j6DpDQKhrsaz69yk5bOcFfjOXe6tHSeUFXjOYOktHSGu1phkBkkHT6pcWa4q0gOn9S4s+euIjl8UuPOcFeRHD6pcWe4q0gOn9S4M9xVJIdPatx5QlVFcvikxp3hrmL5BdwaZ7ZlJKlAhrskFchwl6QCGe6SVCBPqKpIziujcWe4qzjOKyPZllGBnFdGMtxVIOeVkQx3Fch5ZSTDXQVyXhnJE6oqkPPKSIa7CtVtXhmHR2qcGO4FMbwW5vBIjRvDvRBtD69hvzEtNjyyDftHWipPqBaizWO7596YZk6fIfnZG9PBYzO1PYfDIzVuDPdCtDm8VuKNyeGRGjd9hXtEbI+I4xFxIiL2dlm/LiI+GRHHIuJLEfGi+kvVYtoSXgePzbD1miNs2PsRtl5zhIPHZlbkjcnhkRo3PcM9IlYB7wYuAy4BroyIS+Zt9hbg5szcAuwC/rruQrW4NoTXQu2Xycec13X7Ot+YdmyZYv/OzUxNThDA1OQE+3dutt+uYvVzQvVS4ERm3gMQETcBVwB3d2yTwOOq3x8PnKqzyHGw3BOKbRjbvVD75fxzz2HivFVnrRvGG5Nfu6dx0k+4TwH3dtw+CTxz3jZvA/4tIl4P/BzwglqqGxN1jXRpengt1Gb53pmHuO5lz2j0G5PUNv2Ee3RZlvNuXwnckJl/ERG/CnwgIp6WmT8564EidgO7AdatWzdIvUUal2F6aycnmOkS8GsnJxr/xiS1TT8nVE8CF3XcvpBHtl2uBm4GyMzPAo8GVs9/oMw8kJnTmTm9Zs2awSouUJtHuixFG84LSKXoJ9zvADZGxIaIeBSzJ0wPzdvmf4DnA0TEU5kN9wfqLLRkbRnpslye1JRWTs+2TGb+OCJeBxwGVgHXZ+ZdEfF24GhmHgL+FHhvRPwxsy2bqzJzfutGC9izbdNZPXco94jW9ou0MvqafiAzbwNum7fsrR2/3w1srbe08dGGkS6S2sW5ZRrCI1pJdXL6AUkqkOEuSQUy3CWpQIa7JBXIcJekAhnuklQgw12SCmS4S1KBDHdJKpDhLkkFMtwlqUCGuyQVyHCXpAI5K2SH5X5JtSQ1heFeqetLqiWpCWzLVBb7kmpJahvDvbLQl1HPnD7DwWMzK1yNJC2P4V5Z7Muo9916pwEvqVUM98qebZuYOG9V13W2ZyS1jSdUK3MnTd/wwS90Xb9Q26YfjsKRtNKKO3I/eGyGrdccYcPej7D1miNLaqfs2DLF1ALtmcXaNr3q2XfrncycPkPys1E4tnkkDVNR4V5HkHZrz0yct4o92zYNVJOjcCSNQlHhXkeQ7tgyxf6dm5manCCAqckJ9u/cPHAbZaF2znLaPJLUS1E997qCdMeWqdp64msnJ5jp8vz9tnns10saRFFH7gsF5qD98josp81jv17SoIoK97r75XVYTptn0DbTck4qSypDUW2ZucBsWhtj0DbPIG0m58iRBIWFO9TbLx+1Qfr1ix3tl7JfJPVWVFumNIO0mRydIwkM90YbpF/fxJPKklZecW2Z0iy1zbRn26azeu4w+pPKklae4V6Ypp5UlrSyDPcClXRSWdJgDPcevEJUUhv1dUI1IrZHxPGIOBERexfY5qURcXdE3BUR/1hvmaPhFaKS2qpnuEfEKuDdwGXAJcCVEXHJvG02AvuArZn5K8AbhlDrinNGR0lt1c+R+6XAicy8JzN/BNwEXDFvmz8A3p2Z3wXIzPvrLXM0HDMuqa36Cfcp4N6O2yerZZ2eAjwlIj4TEbdHxPZuDxQRuyPiaEQcfeCBBwareAU5ZlxSW/UT7tFlWc67fS6wEXgOcCXwvoiYfMSdMg9k5nRmTq9Zs2apta64Jk5EJkn96Ge0zEngoo7bFwKnumxze2Y+BHw9Io4zG/Z31FLliDhmXFJb9RPudwAbI2IDMAPsAn573jYHmT1ivyEiVjPbprmnzkJHZbEx4w6TlNRUPcM9M38cEa8DDgOrgOsz866IeDtwNDMPVeteGBF3Aw8DezLz28MsfNScWldSk0Xm/Pb5ypiens6jR4+O5LnrsPWaI12n452anOAze583gookjYOI+HxmTvfazlkhB+QwSUlNZrgPyGGSkprMcB+QwyQlNZkThw3IYZKSmsxwXwan1pXUVLZlJKlAhrskFchwl6QCGe6SVCDDXZIKZLhLUoEMd0kqkOEuSQUy3CWpQIa7JBXIcJekAhnuklQgw12SCmS4S1KBDHdJKpDhLkkFMtwlqUCGuyQVyHCXpAIZ7pJUIMNdkgpkuEtSgQx3SSqQ4S5JBTLcJalAhrskFchwl6QCGe6SVCDDXZIK1Fe4R8T2iDgeESciYu8i270kIjIipusrUZK0VD3DPSJWAe8GLgMuAa6MiEu6bPdY4I+Az9VdpCRpafo5cr8UOJGZ92Tmj4CbgCu6bPcO4F3AD2usT5I0gHP72GYKuLfj9kngmZ0bRMQW4KLM/NeIeGON9XV18NgM1x4+zqnTZ1g7OcGebZvYsWVq2E8rSa3RT7hHl2X505UR5wDXAVf1fKCI3cBugHXr1vVX4TwHj82w79Y7OfPQwwDMnD7DvlvvBDDgJanST1vmJHBRx+0LgVMdtx8LPA34VET8N/As4FC3k6qZeSAzpzNzes2aNQMVfO3h4z8N9jlnHnqYaw8fH+jxJKlE/YT7HcDGiNgQEY8CdgGH5lZm5vcyc3Vmrs/M9cDtwOWZeXQYBZ86fWZJyyVpHPUM98z8MfA64DDwZeDmzLwrIt4eEZcPu8D51k5OLGm5JI2jfnruZOZtwG3zlr11gW2fs/yyFrZn26azeu4AE+etYs+2TcN8Wklqlb7CvUnmTpo6WkaSFta6cIfZgDfMJWlhzi0jSQUy3CWpQIa7JBXIcJekAhnuklQgw12SCmS4S1KBDHdJKlBkZu+thvHEEQ8A31ji3VYD3xpCOXWyxnpY4/I1vT6wxkE8OTN7Tqs7snAfREQczcxGfz+rNdbDGpev6fWBNQ6TbRlJKpDhLkkFalu4Hxh1AX2wxnpY4/I1vT6wxqFpVc9dktSfth25S5L60Lhwj4jfioi7IuIn3b5ku2O77RFxPCJORMTejuUbIuJzEfHViPhg9b2vddf4hIj4WPUcH4uIC7ps89yI+ELHzw8jYke17oaI+HrHumeMosZqu4c76jjUsbwp+/EZEfHZ6jXxpYh4Wce6oezHhV5bHevPr/bJiWofre9Yt69afjwittVRz4A1/klE3F3ts09ExJM71nX9m4+gxqsi4oGOWl7Vse4V1eviqxHxihHWeF1HfV+JiNMd61ZkPw4sMxv1AzwV2AR8CpheYJtVwNeAi4FHAV8ELqnW3Qzsqn5/D/CaIdT4LmBv9fte4J09tn8C8B3gMdXtG4CXDHk/9lUj8P0FljdiPwJPATZWv68F7gMmh7UfF3ttdWzzh8B7qt93AR+sfr+k2v58YEP1OKuGsN/6qfG5Ha+318zVuNjffAQ1XgX8VZf7PgG4p/r3gur3C0ZR47ztXw9cv5L7cTk/jTtyz8wvZ+bxHptdCpzIzHsy80fATcAVERHA84Bbqu3+HtgxhDKvqB673+d4CfDRzPzBEGpZyFJr/Kkm7cfM/EpmfrX6/RRwP9DzAo5l6PramrdNZ923AM+v9tkVwE2Z+WBmfh04UT3eiteYmZ/seL3dDlw4hDqWVeMitgEfy8zvZOZ3gY8B2xtQ45XAjUOoYygaF+59mgLu7bh9slr2ROB0Zv543vK6/WJm3gdQ/fsLPbbfxSNfFH9efWS+LiLOH2GNj46IoxFx+1zbiIbux4i4lNkjrK91LK57Py702uq6TbWPvsfsPuvnvnVY6vNcDXy043a3v3nd+q3xN6u/3y0RcdES77tSNVK1tTYARzoWr8R+HNhIvkM1Ij4O/FKXVW/OzH/u5yG6LMtFli/ZYjUu8XGeBGwGDncs3gf8L7NBdQB4E/D2EdW4LjNPRcTFwJGIuBP4vy7bNWE/fgB4RWb+pFpcy36c/1Rdls3/bx/666+Hvp8nIl4OTAPP7lj8iL95Zn6t2/2HXOO/ADdm5oMR8WpmPw09r8/71mEpz7MLuCUzH+5YthL7cWAjCffMfMEyH+IkcFHH7QuBU8zO/zAZEedWR1Rzy2utMSK+GRFPysz7qtC5f5GHeinw4cx8qOOx76t+fTAi/g5446hqrFodZOY9EfEpYAvwTzRoP0bE44CPAG/JzNs7HruW/TjPQq+tbtucjIhzgccze06ln/vWoa/niYgXMPsm+uzMfHBu+QJ/87pDqWeNmfntjpvvBd7Zcd/nzLvvp2qub+55+v177QJe27lghfbjwNralrkD2BizIzoexeyOP5SzZzk+yWyPG+AVQD+fBJbqUPXY/TzHI/p0VZDN9bZ3AP81ihoj4oK5VkZErAa2Anc3aT9Wf98PA+/PzA/NWzeM/dj1tbVI3S8BjlT77BCwqxpNswHYCPxHDTUtucaI2AL8LXB5Zt7fsbzr33xENT6p4+blwJer3w8DL6xqvQB4IWd/8l2xGqs6NzF7YvezHctWaj8ObtRndOf/AL/B7Dvqg8A3gcPV8rXAbR3bvQj4CrPvlG/uWH4xs/9DnQA+BJw/hBqfCHwC+Gr17xOq5dPA+zq2Ww/MAOfMu/8R4E5mw+gfgJ8fRY3Ar1V1fLH69+qm7Ufg5cBDwBc6fp4xzP3Y7bXFbLvn8ur3R1f75ES1jy7uuO+bq/sdBy4b4v8nvWr8ePX/z9w+O9Trbz6CGvcDd1W1fBL45Y77/n61f08ArxxVjdXttwHXzLvfiu3HQX+8QlWSCtTWtowkaRGGuyQVyHCXpAIZ7pJUIMNdkgpkuEtSgQx3SSqQ4S5JBfp/itcakF2kqlUAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 导入数据, 不对数据进行初始化\n",
    "def load_data(filename):\n",
    "    X = []\n",
    "    y = []\n",
    "    with open(filename, 'r') as f:\n",
    "        for line in f:\n",
    "            xi, yi = line.strip('\\n').split('\\t',1) \n",
    "            X.append(float(xi))\n",
    "            y.append(float(yi))\n",
    "    X = np.array(X)\n",
    "    y = np.array(y)\n",
    "    return X, y\n",
    "    \n",
    "filename = 'data'\n",
    "X, y = load_data(filename)\n",
    "print(np.shape(X))\n",
    "print(np.shape(y))\n",
    "# 数据可视化\n",
    "plt.scatter(X, y)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 损失函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# MSE 损失函数\n",
    "def MSE_Loss(X, y):\n",
    "    '''\n",
    "    Computing the MSE loss.\n",
    "    Input:\n",
    "        - X: predictions. N x 1\n",
    "        - y: ground truth. N x 1\n",
    "    Output:\n",
    "        - Loss: the loss.\n",
    "        - dout: the gradient of X.\n",
    "    '''\n",
    "    N = X.shape[0]\n",
    "    Loss = 0.5 * np.dot(X - y, X - y) / N\n",
    "    dout = (X - y) / N\n",
    "    return Loss, dout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5\n",
      "[ 0.   0.  -0.5  0. ]\n"
     ]
    }
   ],
   "source": [
    "# 使用这个来测试 MSE_Loss 是否正确\n",
    "a = np.array([1,1,1,1])\n",
    "b = np.array([1,1,3,1])\n",
    "Loss, dout = MSE_Loss(a, b)\n",
    "print(Loss)\n",
    "print(dout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 两个模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 线性回归模型1 \n",
    "class model_1(object):\n",
    "    '''\n",
    "    The model is y = w0 + w1*x\n",
    "    '''\n",
    "    def __init__(self, w, lr=0.1, mini_batch=5):\n",
    "        self.w = w\n",
    "        self.lr = lr\n",
    "        self.batch = mini_batch\n",
    "        self.loss = []\n",
    "    \n",
    "    def train(self, X, y, num=50):\n",
    "        '''\n",
    "        Utilize SGD to learning the parameters.\n",
    "        Input:\n",
    "            - X: the input data. N x 1\n",
    "            - y: the labels of the data. N x 1\n",
    "            - num: the iteration number.\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        index = random.sample(range(1,N), self.batch)\n",
    "        X_train = X[index]\n",
    "        y_train = y[index]\n",
    "        for i in range(num):\n",
    "            out, cache = self.forward(X_train)\n",
    "            Loss, dout = MSE_Loss(out, y_train)\n",
    "            dw, dx = self.backward(cache, dout)\n",
    "            self.w = self.w - self.lr * dw\n",
    "            self.loss.append(Loss)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        '''\n",
    "        Computing the prediction.\n",
    "        Input: \n",
    "            - X: the input data. N x 1\n",
    "        Ouput:\n",
    "            - y: the prediction. N x 1\n",
    "            - cache: cache X to compute the gradient\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        X = np.c_[np.ones(N), X]\n",
    "        y = np.dot(X, self.w)\n",
    "        cache = X\n",
    "        return y, cache\n",
    "    \n",
    "    def backward(self, cache, dout):\n",
    "        '''\n",
    "        Computing the gradient.\n",
    "        Input:\n",
    "            - dout: the gradient flow from upstream. N x 1\n",
    "        Output:\n",
    "            - dw: the gradient of w. D x 1\n",
    "            - dX: the gradient of X. N x D\n",
    "        '''\n",
    "        X = cache\n",
    "        dw = np.dot(X.T,dout)\n",
    "        dx = None # This gradient is useless, if have time will complete it.\n",
    "        return dw, dx\n",
    "    \n",
    "    def loss_history(self):\n",
    "        return self.loss\n",
    "    \n",
    "    def get_weight(self):\n",
    "        return self.w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The equation of fitting curve is: y = w_0 + w_1 * x\n",
      "weight: (w_0, w_1) = [1.00654209 0.41458616]\n",
      "The final MSE Loss is: 0.003626268364367745\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参数初始化\n",
    "batch = 15 # batch_size of SGD\n",
    "learning_rate = 1e-1 # 初始化步长\n",
    "weight = 0.02 * np.random.randn(2) # 权重初始化\n",
    "iteration = 1000 # 迭代次数\n",
    "\n",
    "p1 = model_1(weight, lr=learning_rate, mini_batch=batch)\n",
    "p1.train(X,y,iteration)\n",
    "pred_y, cache = p1.forward(X)\n",
    "Loss, dout = MSE_Loss(pred_y, y)\n",
    "print('The equation of fitting curve is: y = w_0 + w_1 * x')\n",
    "print('weight: (w_0, w_1) = %s' % p1.get_weight())\n",
    "print('The final MSE Loss is: %s' % p1.loss_history()[-1])\n",
    "\n",
    "# training loss\n",
    "plt.figure()\n",
    "plt.title('Training loss')\n",
    "plt.plot(p1.loss_history(),'o')\n",
    "plt.xlabel('Iteration')\n",
    "plt.show()\n",
    "\n",
    "# 数据可视化\n",
    "plt.figure()\n",
    "plt.title('Visualize')\n",
    "plt.plot(X,y,'o')\n",
    "x = np.linspace(-1,1,200)\n",
    "pred_y, cache = p1.forward(x)\n",
    "plt.plot(x,pred_y)\n",
    "plt.ylabel('y')\n",
    "plt.xlabel('x')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 线性回归模型2\n",
    "class model_2(object):\n",
    "    '''\n",
    "    The model is y = w0 + w1*x\n",
    "    '''\n",
    "    def __init__(self, w, lr=0.1, mini_batch=5):\n",
    "        self.w = w\n",
    "        self.lr = lr\n",
    "        self.batch = mini_batch\n",
    "        self.loss = []\n",
    "    \n",
    "    def train(self, X, y, num=50):\n",
    "        '''\n",
    "        Utilize SGD to learning the parameters.\n",
    "        Input:\n",
    "            - X: the input data. N x 1\n",
    "            - y: the labels of the data. N x 1\n",
    "            - num: the iteration number.\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        index = random.sample(range(1,N), self.batch)\n",
    "        X_train = X[index]\n",
    "        y_train = y[index]\n",
    "        for i in range(num):\n",
    "            out, cache = self.forward(X_train)\n",
    "            Loss, dout = MSE_Loss(out, y_train)\n",
    "            dw, dx = self.backward(cache, dout)\n",
    "            self.w = self.w - self.lr * dw \n",
    "            self.loss.append(Loss)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        '''\n",
    "        Computing the prediction.\n",
    "        Input: \n",
    "            - X: the input data. N x 1\n",
    "        Ouput:\n",
    "            - y: the prediction. N x 1\n",
    "            - cache: cache X to compute the gradient\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        X = np.c_[np.ones(N), X, X * X]\n",
    "        y = np.dot(X, self.w)\n",
    "        cache = X\n",
    "        return y, cache\n",
    "    \n",
    "    def backward(self, cache, dout):\n",
    "        '''\n",
    "        Computing the gradient.\n",
    "        Input:\n",
    "            - dout: the gradient flow from upstream.\n",
    "        Output:\n",
    "            - dw: the gradient of w.\n",
    "            - dx: the gradient of x.\n",
    "        '''\n",
    "        X = cache\n",
    "        dw = np.dot(X.T,dout)\n",
    "        dx = None # This gradient is useless, if have time will complete it.\n",
    "        return dw, dx\n",
    "    \n",
    "    def loss_history(self):\n",
    "        return self.loss\n",
    "    \n",
    "    def get_weight(self):\n",
    "        return self.w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the equation of fitting curve is: y = w_0 + w_1 * x + w_2 * x^2\n",
      "weight = (w_0, w_1, w_2) =  [ 1.09302231  0.37169292 -0.90252719] \n",
      "The final MSE Loss is: 0.0006503172167255549\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参数初始化\n",
    "batch = 5 # batch_size of SGD\n",
    "learning_rate = 1e-1 # 初始化步长\n",
    "weight = 0.02 * np.random.randn(3) # 权重初始化 \n",
    "iteration = 5000# 迭代次数\n",
    "\n",
    "p2 = model_2(weight, lr=learning_rate, mini_batch=batch)\n",
    "p2.train(X,y,iteration)\n",
    "pred_y, cache = p2.forward(X)\n",
    "Loss, dout = MSE_Loss(pred_y, y)\n",
    "print('the equation of fitting curve is: y = w_0 + w_1 * x + w_2 * x^2')\n",
    "print('weight = (w_0, w_1, w_2) =  %s ' % p2.get_weight())\n",
    "print('The final MSE Loss is: %s' % p2.loss_history()[-1])\n",
    "\n",
    "# training loss\n",
    "plt.figure()\n",
    "plt.title('Training loss')\n",
    "plt.plot(p2.loss_history(),'o')\n",
    "plt.xlabel('Iteration')\n",
    "plt.show()\n",
    "\n",
    "# 数据可视化\n",
    "plt.figure()\n",
    "plt.title('Visualize')\n",
    "plt.plot(X,y,'o')\n",
    "x = np.linspace(-1,1,200)\n",
    "pred_y, cache = p2.forward(x)\n",
    "plt.plot(x,pred_y)\n",
    "plt.ylabel('y')\n",
    "plt.xlabel('x')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结：从上面的实验中我们可以得到，对于这组数据在使用梯度下降 500 个 iteration 后，两者最终的 MSE loss 相差不大，都可以比较好的拟合曲线。但是不同的是使用一次函数进行梯度下降的时候解比较稳定，而使用二次曲线进行拟合的时候解不稳定，经常会出现过拟合的情况，可以考虑增加数据或者加入正则项减弱这个情况。从 Loss 曲线上看，两者很快就进入了梯度消失，所以如果我们期望更多的学习，我们可以考虑使用 BN 或者其他的方法缓解梯度消失问题。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "torch",
   "language": "python",
   "name": "torch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
